package utils

import (
	"boy-go/modules/generator/constants"
	"boy-go/modules/generator/model"
	"boy-go/modules/generator/vo"
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/jinzhu/copier"
	"go/format"
	"os"
	"strings"
	"text/template"
)

func _buildTemplateTableData(table model.GenTable, tableColumns []*model.GenTableColumn) *vo.TemplateData {
	data := &vo.TemplateData{}
	err := copier.Copy(&data, table)
	if err != nil {
		panic(fmt.Errorf("复制数据失败: %w", err))
		return nil
	}
	columns := make([]vo.TemplateTableColumn, 0)
	pkcolumns := make([]vo.TemplateTableColumn, 0)
	for _, column := range tableColumns {
		temp := &vo.TemplateTableColumn{}
		err := copier.Copy(temp, column)
		if err != nil {
			panic(fmt.Errorf("复制数据失败: %w", err))
			continue
		}
		voStructField := column.StructField
		voStructType := column.StructType

		if arraysContains(constants.COLUMNTYPE_TIME, getDbType(column.ColumnType)) {
			voStructType = "string"
			colName := column.ColumnName
			colNames := strings.Split(colName, "_")
			if len(colNames) > 1 {
				lastName := colNames[len(colNames)-1]
				if lastName == "time" {
					colNames[len(colNames)-1] = "at"
					colName = ""
					for i := 0; i < len(colNames); i++ {
						colName += colNames[i] + "_"
					}
					temp.StructField = toUpperFirst(toCamelCase(colName))
				}
			}
		}
		temp.VoStructField = voStructField
		temp.VoStructType = voStructType

		if column.IsPk == "1" {
			pkcolumns = append(pkcolumns, *temp)
		}
		columns = append(columns, *temp)
	}
	data.Fields = columns
	data.PkFields = pkcolumns
	data.PermissionPrefix = permissionPrefix(*data.ModuleName, *data.BusinessName)
	data.Dicts = getDicts(table, tableColumns)
	data.DictsNoSymbol = strings.Replace(data.Dicts, "'", "", -1)
	if table.Options != nil {
		options := map[string]interface{}{}
		err = json.Unmarshal([]byte(*table.Options), &options)
		if err == nil {
			pid, have := options["parentMenuId"]
			if have {
				data.ParentMenuId = int64(pid.(float64))
			}
		}
	}
	return data
}

func GeneratorByType(table model.GenTable, tableColumns []*model.GenTableColumn, subTable *model.GenTable, subTableColumns []*model.GenTableColumn, typeVal string, className string) string {
	// 加载模板文件
	tmpl := createTempl(typeVal, className)
	data := _buildTemplateTableData(table, tableColumns)
	if *table.TplCategory == constants.TPL_SUB && subTable != nil {
		data.IsSub = true
		data.SubTable = _buildTemplateTableData(*subTable, subTableColumns)
		subTableFkField := convertStructName(*table.SubTableFkName)
		data.SubTableFkField = *subTableFkField
		for _, column := range subTableColumns {
			if column.StructField == *subTableFkField {
				data.SubTableFkFieldType = column.StructType
				break
			}
		}
	}
	result := renderTemplate(tmpl, typeVal, *data)
	return result
}

func createTempl(mode string, name string) *template.Template {
	tmplByte, err := os.ReadFile("./modules/generator/templates/" + mode + "/" + name + "." + mode + ".tmpl")
	if err != nil {
		fmt.Println("read tmpl failed, err:", err)
		return nil
	}
	funcMap := template.FuncMap{
		"lowerFirst": toLowerFirst,
		"upperFirst": toUpperFirst,
	}
	tmpl := template.Must(template.New(name).Funcs(funcMap).Parse(string(tmplByte)))
	return tmpl
}

// 渲染模版
func renderTemplate(tmpl *template.Template, name string, data vo.TemplateData) string {
	var buf bytes.Buffer
	// 执行模板渲染
	if err := tmpl.Execute(&buf, data); err != nil {
		panic(fmt.Errorf("渲染 "+name+" 模板失败: %w", err))
	}
	if name == "js" || name == "vue" || name == "sql" {
		return string(buf.Bytes())
	}
	formatted, err := format.Source(buf.Bytes())
	if err != nil {
		return ""
	}
	return string(formatted)
}
